﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Zhy.DigitaPlatform.DeviceAccess.Base;
using Zhy.DigitaPlatform.Entities;

namespace Zhy.DigitaPlatform.DeviceAccess.Transfer
{
    /// <summary>
    /// 串口通讯类
    /// </summary>
    internal class SerialUnit : TransferObject
    {
        /// <summary>
        /// 串口通讯对象
        /// </summary>
        SerialPort serialPort;
        /// <summary>
        /// 初始化
        /// </summary>
        public SerialUnit()
        {
            serialPort = new SerialPort();
            this.TUnit = serialPort;
        }

        /// <summary>
        /// 通讯参数配置方法
        /// 端口号、波特率、数据位、校验位、停止位等
        /// </summary>
        /// <param name="props">设备的组件通讯属性集合</param>
        /// <returns></returns>
        internal override Result Config(List<DevicePropItemEntity> props)
        {
            // 端口名称、波特率、数据位、校验位、停止位
            Result result = new Result();
            try
            {
                foreach (var item in props)
                {
                    object v = null;
                    // 反射获取对应名称的通讯属性
                    PropertyInfo pi = serialPort.GetType().GetProperty(item.PropName.Trim(), BindingFlags.Public | BindingFlags.Instance);
                    if (pi == null) continue; // 如果属性没找到就不设置

                    Type propType = pi.PropertyType; // 获取通讯属性的数据类型
                    if (propType.IsEnum)
                    {   // 设置枚举值
                        v = Enum.Parse(propType, item.PropValue.Trim() as string);
                    }
                    else
                    {   // 设置转换值
                        v = Convert.ChangeType(item.PropValue.Trim(), propType);
                    }
                    pi.SetValue(serialPort, v); // 给通讯对象的属性设置值
                }

            }
            catch (Exception ex)
            {
                result.Status = false;
                result.Message = ex.Message;
            }

            return result;
        }

        /// <summary>
        /// 连接
        /// </summary>
        /// <param name="trycount">重试次数</param>
        /// <returns></returns>
        internal override Result Connect(int trycount = 30)
        {
            Result result = new Result();
            try
            {
                int count = 0;
                while (count < trycount) // 循环重连
                {
                    if (serialPort.IsOpen) // 判断本地串口是否打开
                        break;

                    try
                    {
                        serialPort.Open(); // 打开串口
                        break;
                    }
                    catch (System.IO.IOException)
                    {
                        Task.Delay(1).GetAwaiter().GetResult(); // 串口打开失败等待一下
                        count++;
                    }
                }
                if (serialPort == null || !serialPort.IsOpen) // 判断串口是否打开成功
                    throw new Exception("串口打开失败");

                ConnectState = true;
            }
            catch (Exception e)
            {
                result.Status = false;
                result.Message = e.Message;
            }
            return result;
        }

        /// <summary>
        /// 发送和读取数据
        /// </summary>
        /// <param name="req">要发送的数据</param>
        /// <param name="receiveLen">正常返回数据长度</param>
        /// <param name="errorLen">异常返回数据长度</param>
        /// <param name="timeout">超时时间</param>
        /// <returns></returns>
        internal override Result<List<byte>> SendAndReceived(List<byte> req, int receiveLen, int errorLen, int timeout = 5000)
        {
            Result<List<byte>> result = new Result<List<byte>>(); // 实例化通讯结果数据对象
            // 发送
            serialPort.Write(req.ToArray(), 0, req.Count); // 发送报文数据

            List<byte> respBytes = new List<byte>(); // 接收报文数据对象
            try
            {
                serialPort.ReadTimeout = timeout; // 设置超时时间
                // 循环接收返回数据
                while (respBytes.Count < Math.Max(receiveLen, errorLen)) // 判断是否满足正常和异常的接收长度
                {
                    byte data = (byte)serialPort.ReadByte(); // 读取返回数据
                    respBytes.Add(data);
                }
            }
            catch (TimeoutException)
            {
                if (respBytes.Count != errorLen && respBytes.Count != receiveLen) // 判断接收的报文长度有误
                {
                    result.Status = false;
                    result.Message = "接收报文超时";
                }
            }
            catch (Exception e)
            {
                // 异常：一定时间内没有拿到字节数据
                result.Status = false;
                result.Message = e.Message;
            }
            finally
            {
                result.Data = respBytes;
            }
            return result;
        }

        /// <summary>
        /// 关闭连接
        /// </summary>
        internal override Result Close()
        {
            if (serialPort != null)
                serialPort.Close();

            this.ConnectState = false;

            return new Result();
        }
    }
}
